#!/usr/bin/perl

# -*- mode: perl; cperl-continued-brace-offset: -4; indent-tabs-mode: nil; -*-
# vim:shiftwidth=2:tabstop=8:expandtab:textwidth=78:softtabstop=4:ai:

#
# This is the command-line interface to the Spine Data Dictionary. It
# retrieves the metadata provided by the post-commit hook and provides useful
# ways to access that data.
#
# Written by Phil Dibowitz <phil@ticketmaster.com>
#   Wed Jan  2 13:20:01 PST 2008
#

use strict;
use warnings;
use Getopt::Long qw(:config bundling);
use YAML::Syck;
use Data::Dumper;

use constant VERSION => '1.0';
use constant DEFAULT_URI => '/tmp/spine.metadata';
use constant MODE_LIST_KEYS => 0;
use constant MODE_LIST_TAGS => 1;
use constant MODE_KEY_INFO => 2;

sub get_metadata
{
    my $uri = shift;
    my $raw;

    if ($uri =~ m/^(?:http|ftp):\/\//) {
        use LWP::UserAgent;
        my $ua = new LWP::UserAgent;
        $ua->timeout(5);
        $ua->agent('spine-dd');
        my $response = $ua->get($uri);
        unless ($response->is_success) {
            die "Failed to retreive $uri with LWP::Agent: "
                . $response->code;
        }
        $raw = $response->content;
    } elsif ($uri =~ m/^file:\/\// || $uri =~ m/^\//) {
        my $filename = $uri;
        $filename =~ s/^file:\/\///;
        open(FILE, "<$filename") || die "Can't open $filename: $!";
        $raw = join('',<FILE>);
        close(FILE);
    } else {
        die "Couldn't determine protocol handler for URI $uri";
    } 

    # This function will eventually retrieve metadata over HTTP
    # but this is just testing
    my $data = YAML::Syck::Load($raw);

    return $data;
}

sub list_keys_from_tag
{
    my ($data,$tag) = @_;

    print "The following keys have been tagged with \"$tag\":\n\t";
    print join("\n\t", keys(%{$data->{'tagmap'}->{$tag}})) . "\n";
}

sub list_keys
{
    my $data = shift;

    print "All Keys (with metadata):\n\t";
    print join("\n\t", keys(%{$data->{'keys'}})) . "\n";
}

sub list_tags
{
    my $data = shift;

    print "All Tags:\n\t";
    print join("\n\t", keys(%{$data->{'tagmap'}})) . "\n";
}

sub list_tags_from_key
{
}

sub dump_key
{
    my ($data, $key) = @_;

    print "Metadata for key \"$key\"\n";
    foreach my $loc (keys(%{$data->{'keys'}->{$key}})) {
        print "  **** LOCATION: $loc\n\t";
        print Dumper($data->{'keys'}->{$key}->{$loc});
    }
}

sub usage
{
    print "$0 v" . VERSION . "\n\n";
    print "One of the following modes must be specified.\n\n";
    print "     --key-info <key>\n";
    print "         Print information about <key>. Also can be specified as"
            . " --key.\n\n";
    print "     --list-keys\n";
    print "         Print a list of all keys.\n\n";
    print "     --list-tags\n";
    print "         Print a lsit of all tags.\n\n";
    print "And the following options are available.\n\n";
    print "     -d, --debug\n";
    print "         Enable debugging.\n\n";
    print "     -h, --help\n";
    print "         Print this message and exit.\n\n";
    print "     -u, --uri <uri>\n";
    print "         Retreive metadata from <uri>.\n\n";
    print "     -v, --version\n";
    print "         Print version and exit.\n\n";

    exit;
}

my $opts = {};
GetOptions($opts,
    'debug|d',
    'help|h',
    'key-info|key=s',
    'list-keys',
    'list-tags',
    'tag=s',
    'uri|u=s',
    'version|v',
    ) || usage();

if (exists($opts->{'version'})) {
    print "$0 v" . VERSION . "\n";
    exit;
}

if (exists($opts->{'help'})) {
    usage();
}

my $mode;

my @modes = qw(list-keys list-tags key-info);
my $n = 0;

foreach my $mode (@modes) {
    if (exists($opts->{$mode})) {
        $n++;
    }
}

if ($n > 1) {
    die("Only one of --list-keys or --list-tags allowed at a time");
} elsif ($n < 0) {
    die("No mode options specified");
} elsif (exists($opts->{'list-keys'})) {
    $mode = MODE_LIST_KEYS;
} elsif (exists($opts->{'list-tags'})) {
    $mode = MODE_LIST_TAGS;
} elsif (exists($opts->{'key-info'})) {
    $mode = MODE_KEY_INFO;
} else {
    die("Couldn't deteremine mode\n");
}

my $uri = DEFAULT_URI;
if (exists($opts->{'uri'})) {
    $uri = $opts->{'uri'};
}

my $data = get_metadata($uri);

if ($mode == MODE_LIST_KEYS) {
    if (exists($opts->{'tag'})) {
        list_keys_from_tag($data,$opts->{'tag'});
    } else {
        list_keys($data);
    }
} elsif ($mode == MODE_LIST_TAGS) {
    list_tags($data);
} elsif ($mode == MODE_KEY_INFO) {
    dump_key($data, $opts->{'key-info'});
}

